﻿using System;
using System.IO;
using Function.SerializedPropertyAttribute;
using SCore.Util;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEngine;

namespace Editor.Gmx.AutoGroup
{
    [CustomEditor(typeof(AutoGroupSetting))]
    public class AutoGroupSettingEditor : ObjectDrawEditor<AutoGroupSetting>
    {
    }

    [CreateAssetMenu(fileName = "AutoGroupSetting", menuName = "ScriptableObject/Framework/AutoGroupSetting",
        order = 1)]
    public class AutoGroupSetting : SingleScriptableObject<AutoGroupSetting>
    {
        [Foldout("收集设置", true)] [Head("根路径")] [SerializeField]
        public string _autoGroupRoot = "Assets/Art";

        [Head("忽略的文件后缀")] [SerializeField]
        public string[] _ingoreFileExtension = new[] { ".meta", ".DS_Store", ".~", ".cs" };

        [Head("是否展示导入Group的进度")] [SerializeField]
        public bool _showImportProgressBar = true;

        [Head("规则文件名")] [SerializeField] public string _sign = "__auto_group.txt";

        [Head("文件名标签前缀")] [SerializeField] public string _directoryLable = "ag__d_";

        [Head("文件标签前缀")] [SerializeField] public string _fileLable = "ag__f_";


        [Head("AutoGroupName")] public string _autoGroupName = "AutoGroup";

        [Foldout("构建参数设置", true)] [Head("组设置")]
        public AddressableAssetGroupTemplate _groupTemplate;

        [Head("总设置")] public AutoAddressableTemplate _addressableTemplate;

        [Head("缓存设置")] public CacheInitializationSettings _cacheInitializationSettings;

        public bool IsRuleLable(string lable)
        {
            return lable.Contains("ag__");
        }

        public bool IsSignFile(string assetPath)
        {
            return assetPath.Contains(_sign);
        }

        public bool IsAssetIgnored(string assetPath)
        {
            //文件夹不处理
            if (Directory.Exists(assetPath))
            {
                return true;
            }

            //_sign 文件不处理
            if (assetPath.Contains(_sign.Substring(0, _sign.Length - 4)))
            {
                return true;
            }

            //特殊后缀不处理
            foreach (var extension in _ingoreFileExtension)
            {
                if (assetPath.EndsWith(extension))
                {
                    return true;
                }
            }

            return false;
        }

        public bool IsAssetInRoot(string assetPath)
        {
            return assetPath.Contains(_autoGroupRoot) ||
                   assetPath.Contains(_autoGroupRoot.Replace('/', '\\'));
        }

        public bool IsNeedAuto(string assetPath)
        {
            var assetName = Path.GetFileName(assetPath);
            var rulePath = assetPath.Replace(assetName, _sign);
            return File.Exists(rulePath);
        }


        private string GetDirectoryLabelName(string assetPath)
        {
            var directoryPath = Path.GetDirectoryName(assetPath)?.ToLower();
            if (directoryPath == null)
            {
                Debug.LogError($"GetDirectoryLabelName error: {assetPath}");
                return "";
            }

            directoryPath = directoryPath.Replace(Path.DirectorySeparatorChar.ToString(), "_");
            directoryPath = directoryPath.Trim();

            return _directoryLable + directoryPath;
        }

        private string GetFileLabelName(string assetName)
        {
            return (_fileLable + assetName).ToLower().Trim();
        }

        private bool RuleExecute(string rulePath, string assetName, string assetPath, out string lable)
        {
            lable = string.Empty;
            //提取__auto_group文件
            string fileContents = File.ReadAllText(rulePath);
            string[] sections = fileContents.Split(new string[] { "[black]", "[white]" },
                StringSplitOptions.RemoveEmptyEntries);

            //内容为空走一个bundle
            if (sections.Length == 0)
            {
                lable = GetDirectoryLabelName(assetPath);
                return true;
            }

            string notExtensionName = Path.GetFileNameWithoutExtension(assetName);

            //黑名单逻辑
            string[] rosterLine = default;
            string roster = default;
            if (sections.Length > 0 && !string.IsNullOrEmpty(sections[0]))
            {
                roster = sections[0].Trim();
                rosterLine =
                    roster.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var blackName in rosterLine)
                {
                    if (notExtensionName == blackName)
                    {
                        return false;
                    }

                    if (blackName == "*")
                    {
                        return false;
                    }
                }
            }

            //白名单内容为空走一个bundle
            if (sections.Length < 2 || string.IsNullOrEmpty(sections[1].Trim()))
            {
                lable = GetDirectoryLabelName(assetPath);
                return true;
            }

            roster = sections[1].Trim();
            rosterLine = roster.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
            //白名单内容为空走一个bundle
            if (roster.Length == 0)
            {
                lable = GetDirectoryLabelName(assetPath);
                return true;
            }

            //存在白名单 白名单规则覆盖  采用单个bundle 模式
            foreach (var whiteName in rosterLine)
            {
                bool white = notExtensionName == whiteName || whiteName == "*";
                if (white)
                {
                    lable = GetFileLabelName(assetName);
                    return true;
                }
            }

            return false;
        }

        public bool RuleExecute(string assetPath, out string lable)
        {
            var assetName = Path.GetFileName(assetPath);
            var rulePath = assetPath.Replace(assetName, _sign);
            return RuleExecute(rulePath, assetName, assetPath, out lable);
        }

        public void SyncSettings()
        {
            var settings = AddressableAssetSettingsDefaultObject.Settings;
            AutoGroupRule.TryGetGroup(settings, _autoGroupName, out var group);
            BundledAssetGroupSchema runBuildAssetSchema = null;
            BundledAssetGroupSchema tempBuildAssetSchema = null;
            if (group != null)
            {
                runBuildAssetSchema = group.GetSchema<BundledAssetGroupSchema>();
            }

            if (_groupTemplate != null)
            {
                tempBuildAssetSchema =
                    (BundledAssetGroupSchema)_groupTemplate.GetSchemaByType(typeof(BundledAssetGroupSchema));
            }

            bool isChange = false;
            if (tempBuildAssetSchema != null && runBuildAssetSchema != null)
            {
                if (runBuildAssetSchema.InternalBundleIdMode != tempBuildAssetSchema.InternalBundleIdMode)
                {
                    runBuildAssetSchema.InternalBundleIdMode = tempBuildAssetSchema.InternalBundleIdMode;
                    isChange = true;
                }

                if (runBuildAssetSchema.Compression != tempBuildAssetSchema.Compression)
                {
                    runBuildAssetSchema.Compression = tempBuildAssetSchema.Compression;
                    isChange = true;
                }

                if (runBuildAssetSchema.IncludeAddressInCatalog != tempBuildAssetSchema.IncludeAddressInCatalog)
                {
                    runBuildAssetSchema.IncludeAddressInCatalog = tempBuildAssetSchema.IncludeAddressInCatalog;
                    isChange = true;
                }

                if (runBuildAssetSchema.IncludeGUIDInCatalog != tempBuildAssetSchema.IncludeGUIDInCatalog)
                {
                    runBuildAssetSchema.IncludeGUIDInCatalog = tempBuildAssetSchema.IncludeGUIDInCatalog;
                    isChange = true;
                }

                if (runBuildAssetSchema.IncludeLabelsInCatalog != tempBuildAssetSchema.IncludeLabelsInCatalog)
                {
                    runBuildAssetSchema.IncludeLabelsInCatalog = tempBuildAssetSchema.IncludeLabelsInCatalog;
                    isChange = true;
                }

                if (runBuildAssetSchema.InternalIdNamingMode != tempBuildAssetSchema.InternalIdNamingMode)
                {
                    runBuildAssetSchema.InternalIdNamingMode = tempBuildAssetSchema.InternalIdNamingMode;
                    isChange = true;
                }

                if (runBuildAssetSchema.AssetBundledCacheClearBehavior !=
                    tempBuildAssetSchema.AssetBundledCacheClearBehavior)
                {
                    runBuildAssetSchema.AssetBundledCacheClearBehavior =
                        tempBuildAssetSchema.AssetBundledCacheClearBehavior;
                    isChange = true;
                }

                if (runBuildAssetSchema.IncludeInBuild != tempBuildAssetSchema.IncludeInBuild)
                {
                    runBuildAssetSchema.IncludeInBuild = tempBuildAssetSchema.IncludeInBuild;
                    isChange = true;
                }

                if (runBuildAssetSchema.ForceUniqueProvider != tempBuildAssetSchema.ForceUniqueProvider)
                {
                    runBuildAssetSchema.ForceUniqueProvider = tempBuildAssetSchema.ForceUniqueProvider;
                    isChange = true;
                }

                if (runBuildAssetSchema.UseAssetBundleCache != tempBuildAssetSchema.UseAssetBundleCache)
                {
                    runBuildAssetSchema.UseAssetBundleCache = tempBuildAssetSchema.UseAssetBundleCache;
                    isChange = true;
                }

                if (runBuildAssetSchema.UseAssetBundleCrc != tempBuildAssetSchema.UseAssetBundleCrc)
                {
                    runBuildAssetSchema.UseAssetBundleCrc = tempBuildAssetSchema.UseAssetBundleCrc;
                    isChange = true;
                }

                if (runBuildAssetSchema.UseAssetBundleCrcForCachedBundles !=
                    tempBuildAssetSchema.UseAssetBundleCrcForCachedBundles)
                {
                    runBuildAssetSchema.UseAssetBundleCrcForCachedBundles =
                        tempBuildAssetSchema.UseAssetBundleCrcForCachedBundles;
                    isChange = true;
                }

                if (runBuildAssetSchema.Timeout != tempBuildAssetSchema.Timeout)
                {
                    runBuildAssetSchema.Timeout = tempBuildAssetSchema.Timeout;
                    isChange = true;
                }

                if (runBuildAssetSchema.ChunkedTransfer != tempBuildAssetSchema.ChunkedTransfer)
                {
                    runBuildAssetSchema.ChunkedTransfer = tempBuildAssetSchema.ChunkedTransfer;
                    isChange = true;
                }

                if (runBuildAssetSchema.RedirectLimit != tempBuildAssetSchema.RedirectLimit)
                {
                    runBuildAssetSchema.RedirectLimit = tempBuildAssetSchema.RedirectLimit;
                    isChange = true;
                }

                if (runBuildAssetSchema.RetryCount != tempBuildAssetSchema.RetryCount)
                {
                    runBuildAssetSchema.RetryCount = tempBuildAssetSchema.RetryCount;
                    isChange = true;
                }


                if (runBuildAssetSchema.BundleMode != tempBuildAssetSchema.BundleMode)
                {
                    runBuildAssetSchema.BundleMode = tempBuildAssetSchema.BundleMode;
                    isChange = true;
                }

                if (runBuildAssetSchema.BundleNaming != tempBuildAssetSchema.BundleNaming)
                {
                    runBuildAssetSchema.BundleNaming = tempBuildAssetSchema.BundleNaming;
                    isChange = true;
                }

                if (runBuildAssetSchema.AssetLoadMode != tempBuildAssetSchema.AssetLoadMode)
                {
                    runBuildAssetSchema.AssetLoadMode = tempBuildAssetSchema.AssetLoadMode;
                    isChange = true;
                }

                if (tempBuildAssetSchema.BuildPath.GetName(settings) != _addressableTemplate._remoteCatalogBuildPath)
                {
                    tempBuildAssetSchema.BuildPath.SetVariableByName(settings,
                        _addressableTemplate._remoteCatalogBuildPath);
                    EditorUtility.SetDirty(_addressableTemplate);
                    AssetDatabase.SaveAssetIfDirty(_addressableTemplate);
                }

                if (tempBuildAssetSchema.LoadPath.GetName(settings) != _addressableTemplate._remoteCatalogLoadPath)
                {
                    tempBuildAssetSchema.LoadPath.SetVariableByName(settings,
                        _addressableTemplate._remoteCatalogLoadPath);
                    EditorUtility.SetDirty(_addressableTemplate);
                    AssetDatabase.SaveAssetIfDirty(_addressableTemplate);
                }

                if (runBuildAssetSchema.BuildPath.GetName(settings) != _addressableTemplate._remoteCatalogBuildPath)
                {
                    runBuildAssetSchema.BuildPath.SetVariableByName(settings,
                        _addressableTemplate._remoteCatalogBuildPath);
                    EditorUtility.SetDirty(_addressableTemplate);
                    AssetDatabase.SaveAssetIfDirty(_addressableTemplate);
                }

                if (runBuildAssetSchema.LoadPath.GetName(settings) != _addressableTemplate._remoteCatalogLoadPath)
                {
                    runBuildAssetSchema.LoadPath.SetVariableByName(settings,
                        _addressableTemplate._remoteCatalogLoadPath);
                    EditorUtility.SetDirty(_addressableTemplate);
                    AssetDatabase.SaveAssetIfDirty(_addressableTemplate);
                }

                if ((settings.InitializationObjects.Count > 0 &&
                     settings.InitializationObjects[0] != _cacheInitializationSettings) ||
                    settings.InitializationObjects.Count == 0)
                {
                    settings.InitializationObjects.Clear();
                    settings.InitializationObjects.Add(_cacheInitializationSettings);
                    isChange = true;
                }
            }

            if (isChange)
            {
                EditorUtility.SetDirty(group);
                AssetDatabase.SaveAssetIfDirty(group);
            }

            _addressableTemplate.SyncSettings(settings);
        }
    }
}